home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmSysCall.c < prev    next >
C/C++ Source or Header  |  1991-08-13  |  39KB  |  1,341 lines

  1. /* vmSysCall.c -
  2.  *
  3.  *     This file contains routines that handle virtual memory system
  4.  *    calls.
  5.  *
  6.  * Copyright (C) 1985 Regents of the University of California
  7.  * All rights reserved.
  8.  */
  9.  
  10.  
  11. #ifndef lint
  12. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmSysCall.c,v 9.20 91/08/13 12:44:22 shirriff Exp $ SPRITE (Berkeley)";
  13. #endif not lint
  14.  
  15. #include <sprite.h>
  16. #include <vm.h>
  17. #include <vmInt.h>
  18. #include <vmTrace.h>
  19. #include <lock.h>
  20. #include <user/vm.h>
  21. #include <sync.h>
  22. #include <sys.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <fs.h>
  26. #include <fsio.h>
  27. #include <sys/mman.h>
  28. #include <stdio.h>
  29. #include <bstring.h>
  30.  
  31. extern Vm_SharedSegTable sharedSegTable;
  32. char     *sprintf();
  33.  
  34. int vmShmDebug = 0;    /* Shared memory debugging flag. */
  35.  
  36. extern int   debugFsStubs; /* Unix compatibility debug flags. */
  37. extern int   debugProcStubs;
  38. extern int   debugSigStubs;
  39. extern int   debugSysStubs;
  40. extern int   debugTimerStubs;
  41. extern int   debugVmStubs;
  42.  
  43. /*
  44.  * Forward declaration.
  45.  */
  46. static ReturnStatus VmMunmapInt _ARGS_((Address startAddr, int length,
  47.     int noError));
  48.  
  49. /*
  50.  * VmVirtAddrParseUnlock calls VmVirtAddrParse and then unlocks
  51.  * the heap page table if necessary, since VmVirtAddrParse may
  52.  * lock it.
  53.  */
  54. #define VmVirtAddrParseUnlock(procPtr, startAddr, virtAddrPtr) \
  55.     {VmVirtAddrParse(procPtr,startAddr, virtAddrPtr); \
  56.     if ((virtAddrPtr)->flags & VM_HEAP_PT_IN_USE) \
  57.         VmDecPTUserCount(procPtr->vmPtr->segPtrArray[VM_HEAP]);}
  58.  
  59. /*
  60.  * Test if an address is not page aligned.
  61.  */
  62. #define BADALIGN(addr) (((int)(addr))&(vm_PageSize-1))
  63.  
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * Vm_PageSize --
  69.  *
  70.  *    Return the hardware page size.
  71.  *
  72.  * Results:
  73.  *    Status from copying the page size out to user space.
  74.  *
  75.  * Side effects:
  76.  *    Copy page size out to user address space.
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80. ReturnStatus
  81. Vm_PageSize(pageSizePtr)
  82.     int    *pageSizePtr;
  83. {
  84.     int            pageSize = vm_PageSize;
  85.  
  86.     return(Vm_CopyOut(4, (Address) &pageSize, (Address) pageSizePtr));
  87. }
  88.  
  89.  
  90. /***************************************************************************
  91.  *
  92.  *    The following two routines, Vm_CreateVA and Vm_DestroyVA, are used
  93.  *    to allow users to add or delete ranges of valid virtual addresses
  94.  *    from their virtual address space.  Since neither of these routiens
  95.  *    are monitored (although they call monitored routines), there are 
  96.  *    potential synchronization problems for users sharing memory who
  97.  *    expand their heap segment.  The problems are caused if two or more
  98.  *    users attempt to simultaneously change the size of the heap segment 
  99.  *    to different sizes. The virtual memory system will not have any 
  100.  *    problems handling the conflicting requests, however the actual range 
  101.  *    of valid virtual addresses is unpredictable.  It is up to the user
  102.  *    to synchronize when expanding the HEAP segment.
  103.  */
  104.  
  105.  
  106. /*
  107.  *----------------------------------------------------------------------
  108.  *
  109.  * Vm_CreateVA --
  110.  *
  111.  *    Validate the given range of addresses.  If necessary the segment
  112.  *    is expanded to make room.
  113.  *
  114.  * Results:
  115.  *    VM_WRONG_SEG_TYPE if tried to validate addresses for a stack or
  116.  *    code segment and VM_SEG_TOO_LARGE if the segment cannot be
  117.  *    expanded to fill the size.
  118.  *
  119.  * Side effects:
  120.  *    None.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124.  
  125. ReturnStatus
  126. Vm_CreateVA(address, size)
  127.     Address address;    /* Address to validate from. */
  128.     int        size;    /* Number of bytes to validate. */
  129. {
  130.     register Vm_Segment *segPtr;
  131.     int            firstPage, lastPage;
  132.     Proc_ControlBlock    *procPtr;
  133.  
  134.     procPtr = Proc_GetCurrentProc();
  135.     firstPage = (unsigned) (address) >> vmPageShift;
  136.     lastPage = (unsigned) ((int) address + size - 1) >> vmPageShift;
  137.  
  138.     segPtr = (Vm_Segment *) procPtr->vmPtr->segPtrArray[VM_HEAP];
  139.  
  140.     /*
  141.      * Make sure that the beginning address falls into the heap segment and
  142.      * not the code segment.
  143.      */
  144.     if (firstPage < segPtr->offset) {
  145.     return(VM_WRONG_SEG_TYPE);
  146.     }
  147.  
  148.     /*
  149.      * Make sure that the ending page is not greater than the highest
  150.      * possible page.  Since there must be one stack page and one page
  151.      * between the stack and the heap, the highest possible heap page is
  152.      * mach_LastUserStackPage - 2 or segPtr->maxAddr, whichever is lower.
  153.      */
  154.     if (lastPage > mach_LastUserStackPage - 2 ||
  155.         address + size - 1 > segPtr->maxAddr) {
  156.     return(VM_SEG_TOO_LARGE);
  157.     }
  158.  
  159.     /*
  160.      * Make pages between firstPage and lastPage part of the heap segment's
  161.      * virtual address space.
  162.      */
  163.     return(VmAddToSeg(segPtr, firstPage, lastPage));
  164. }
  165.  
  166.  
  167. /*
  168.  *----------------------------------------------------------------------
  169.  *
  170.  * Vm_DestroyVA --
  171.  *
  172.  *    Invalidate the given range of addresses.  If the starting address
  173.  *    is too low then an error message is returned.
  174.  *
  175.  * Results:
  176.  *    VM_WRONG_SEG_TYPE if tried to invalidate addresses for a code.
  177.  *
  178.  * Side effects:
  179.  *    None.
  180.  *
  181.  *----------------------------------------------------------------------
  182.  */
  183.  
  184. ReturnStatus
  185. Vm_DestroyVA(address, size)
  186.     Address address;    /* Address to validate from. */
  187.     int        size;    /* Number of bytes to validate. */
  188. {
  189.     register Vm_Segment *segPtr;
  190.     int            firstPage, lastPage;
  191.     Proc_ControlBlock    *procPtr;
  192.  
  193.     procPtr = Proc_GetCurrentProc();
  194.     firstPage = (unsigned) (address) >> vmPageShift;
  195.     lastPage = (unsigned) ((int) address + size - 1) >> vmPageShift;
  196.  
  197.     segPtr = (Vm_Segment *) procPtr->vmPtr->segPtrArray[VM_HEAP];
  198.  
  199.     /*
  200.      * Make sure that the beginning address falls into the 
  201.      * heap segment.
  202.      */
  203.     if (firstPage < segPtr->offset) {
  204.     return(VM_WRONG_SEG_TYPE);
  205.     }
  206.  
  207.     /*
  208.      * Make pages between firstPage and lastPage not members of the segment's
  209.      * virtual address space.
  210.      */
  211.     return(Vm_DeleteFromSeg(segPtr, firstPage, lastPage));
  212. }
  213.  
  214. static int    copySize = 4096;
  215.  
  216. #ifndef CLEAN
  217. static char    buffer[8192];
  218. #endif CLEAN
  219.  
  220. void    SetVal();
  221.  
  222. /*
  223.  * The # construct to turn a variable into a string is not handled correctly
  224.  * on the current ds3100 (non-ansi) compiler/preprocessor set up.
  225.  * This will change when it's handled correctly.
  226.  */
  227. #if defined(__STDC__)
  228. #define SETVAR(var, val) SetVal(#var, val, (int *)&(var))
  229. #else
  230. #define    SETVAR(var, val) SetVal("var", val, (int *)&(var))
  231. #endif /* sun4 */
  232.  
  233.  
  234. /*
  235.  *----------------------------------------------------------------------
  236.  *
  237.  * Vm_Cmd --
  238.  *
  239.  *      This routine allows a user level program to give commands to
  240.  *      the virtual memory system.
  241.  *
  242.  * Results:
  243.  *      None.
  244.  *
  245.  * Side effects:
  246.  *      Some parameter of the virtual memory system will be modified.
  247.  *
  248.  *----------------------------------------------------------------------
  249.  */
  250. ReturnStatus
  251. Vm_Cmd(command, arg)
  252.     int        command;
  253.     int         arg;
  254. {
  255.     int            numBytes;
  256.     ReturnStatus    status = SUCCESS;
  257.     int            numModifiedPages;
  258.  
  259.     switch (command) {
  260.     case VM_COUNT_DIRTY_PAGES:
  261.         numModifiedPages = VmCountDirtyPages();
  262.         if (Vm_CopyOut(sizeof(int), (Address) &numModifiedPages,
  263.                (Address) arg) != SUCCESS) {
  264.         status = SYS_ARG_NOACCESS;
  265.         }
  266.         break;
  267.     case VM_FLUSH_SEGMENT: {
  268.         extern int    vmNumSegments;
  269.         int        intArr[3];
  270.         Vm_Segment    *segPtr;
  271.         int        lowPage;
  272.         int        highPage;
  273.         Vm_VirtAddr    virtAddr;
  274.  
  275.         status = Vm_CopyIn(3 * sizeof(int), (Address)arg, 
  276.                 (Address)intArr);
  277.         if (status != SUCCESS) {
  278.         break;
  279.         }
  280.         if (intArr[0] <= 0 || intArr[0] >= vmNumSegments) {
  281.         status = SYS_INVALID_ARG;
  282.         break;
  283.         }
  284.         segPtr = VmGetSegPtr(intArr[0]);
  285.         if (segPtr->type == VM_STACK) {
  286.         lowPage = mach_LastUserStackPage - segPtr->numPages + 1;
  287.         highPage = mach_LastUserStackPage;
  288.         } else {
  289.         lowPage = segPtr->offset;
  290.         highPage = segPtr->offset + segPtr->numPages - 1;
  291.         }
  292.         if (intArr[1] >= lowPage && intArr[1] <= highPage) {
  293.         lowPage = intArr[1];
  294.         }
  295.         if (intArr[2] >= lowPage && intArr[2] <= highPage) {
  296.         highPage = intArr[2];
  297.         }
  298.         virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  299.         virtAddr.segPtr = segPtr;
  300.         virtAddr.page = lowPage;
  301.         VmFlushSegment(&virtAddr, highPage);
  302.         break;
  303.     }
  304.     case VM_SET_FREE_WHEN_CLEAN:
  305.         SETVAR(vmFreeWhenClean, arg);
  306.         break;
  307.     case VM_SET_MAX_DIRTY_PAGES:
  308.         SETVAR(vmMaxDirtyPages, arg);
  309.         break;
  310.     case VM_SET_PAGEOUT_PROCS:
  311.         SETVAR(vmMaxPageOutProcs, arg);
  312.         break;
  313.         case VM_SET_CLOCK_PAGES:
  314.             SETVAR(vmPagesToCheck, arg);
  315.             break;
  316.         case VM_SET_CLOCK_INTERVAL: {
  317.         SETVAR(vmClockSleep, (int) (arg * timer_IntOneSecond));
  318.             break;
  319.     }
  320.     case VM_SET_COPY_SIZE:
  321.         SETVAR(copySize, arg);
  322.         break;
  323. #ifndef CLEAN
  324.     case VM_DO_COPY_IN:
  325.         (void)Vm_CopyIn(copySize, (Address) arg, buffer);
  326.         break;
  327.     case VM_DO_COPY_OUT:
  328.         (void)Vm_CopyOut(copySize, buffer, (Address) arg);
  329.         break;
  330.     case VM_DO_MAKE_ACCESS_IN:
  331.         Vm_MakeAccessible(0, copySize, (Address) arg, &numBytes,
  332.                   (Address *) &arg);
  333.         bcopy((Address) arg, buffer, copySize);
  334.         Vm_MakeUnaccessible((Address) arg, numBytes);
  335.         break;
  336.     case VM_DO_MAKE_ACCESS_OUT:
  337.         Vm_MakeAccessible(0, copySize, (Address) arg, &numBytes,
  338.                   (Address *) &arg);
  339.         bcopy(buffer, (Address) arg, copySize);
  340.         Vm_MakeUnaccessible((Address) arg, numBytes);
  341.         break;
  342. #endif CLEAN
  343.     case VM_GET_STATS: {
  344. #if defined(ds3100) || defined(ds5000)
  345.         extern unsigned int end;
  346.         /*
  347.          * The decstations have a big hole between the initialized data
  348.          * and the heap, so we can't just subtract the kernel beginning
  349.          * from the end.
  350.          */
  351.         vmStat.kernMemPages = (unsigned int) 
  352.         (vmMemEnd - VMMACH_VIRT_CACHED_START + (unsigned int) &end
  353.          - mach_KernStart) / vm_PageSize;
  354. #else
  355.         vmStat.kernMemPages = 
  356.             (unsigned int)(vmMemEnd - mach_KernStart) / vm_PageSize;
  357. #endif
  358.         if (Vm_CopyOut(sizeof(Vm_Stat), (Address) &vmStat, 
  359.                (Address) arg) != SUCCESS) {
  360.         status = SYS_ARG_NOACCESS;
  361.         }
  362.         break;
  363.     }
  364.     case VM_SET_COW:
  365.         /*
  366.          * It's okay to turn on COW when it's off, but not the other
  367.          * way around.
  368.          */
  369.         if (arg || !vm_CanCOW) {
  370.         SETVAR(vm_CanCOW, arg);
  371.         } else {
  372.         status = GEN_INVALID_ARG;
  373.         }
  374.         break;
  375.     case VM_SET_FS_PENALTY:
  376.         if (arg <= 0) {
  377.         /*
  378.          * Caller is setting an absolute penalty.
  379.          */
  380.         SETVAR(vmCurPenalty, -arg);
  381.         } else {
  382.         SETVAR(vmFSPenalty, arg);
  383.         SETVAR(vmCurPenalty, (vmStat.fsMap - vmStat.fsUnmap) / 
  384.                     vmPagesPerGroup * vmFSPenalty);
  385.         }
  386.         break;
  387.     case VM_SET_NUM_PAGE_GROUPS: {
  388.         int    numPages;
  389.         int curGroup;
  390.         numPages = vmPagesPerGroup * vmNumPageGroups;
  391.         if (arg <= 0) {
  392.         status = GEN_INVALID_ARG;
  393.         break;
  394.         }
  395.         SETVAR(vmNumPageGroups, arg);
  396.         SETVAR(vmPagesPerGroup, numPages / vmNumPageGroups);
  397.         curGroup = (vmStat.fsMap - vmStat.fsUnmap) / vmPagesPerGroup;
  398.         SETVAR(vmCurPenalty, curGroup * vmFSPenalty);
  399.         SETVAR(vmBoundary, (curGroup + 1) * vmPagesPerGroup);
  400.         break;
  401.     }
  402.     case VM_SET_ALWAYS_REFUSE:
  403.         SETVAR(vmAlwaysRefuse, arg);
  404.         break;
  405.     case VM_SET_ALWAYS_SAY_YES:
  406.         SETVAR(vmAlwaysSayYes, arg);
  407.         break;
  408.     case VM_RESET_FS_STATS:
  409.         vmStat.maxFSPages = vmStat.fsMap - vmStat.fsUnmap;
  410.         vmStat.minFSPages = vmStat.fsMap - vmStat.fsUnmap;
  411.         break;
  412.     case VM_SET_COR_READ_ONLY:
  413.         SETVAR(vmCORReadOnly, arg);
  414.         break;
  415.     case VM_SET_PREFETCH:
  416.         SETVAR(vmPrefetch, arg);
  417.         break;
  418.     case VM_SET_USE_FS_READ_AHEAD:
  419.         SETVAR(vmUseFSReadAhead, arg);
  420.         break;
  421.     case VM_START_TRACING: {
  422.         ReturnStatus    status;
  423.         void        VmTraceDaemon();
  424.         Vm_TraceStart    *traceStartPtr;
  425.         extern int        etext;
  426.         char        fileName[100];
  427.         char        hostNum[34];
  428.  
  429.         if (vmTraceFilePtr != (Fs_Stream *)NIL) {
  430.         printf("VmCmd: Tracing already running.\n");
  431.         break;
  432.         }
  433.         vmTracesPerClock = arg;
  434.         printf("Vm_Cmd: Tracing started at %d times per second\n",
  435.             arg);
  436.  
  437.         if (vmTraceBuffer == (char *)NIL) {
  438.         vmTraceBuffer = (char *)malloc(VM_TRACE_BUFFER_SIZE);
  439.         }
  440.         bzero((Address)&vmTraceStats, sizeof(vmTraceStats));
  441.  
  442.         traceStartPtr = (Vm_TraceStart  *)vmTraceBuffer;
  443.         traceStartPtr->recType = VM_TRACE_START_REC;
  444.         traceStartPtr->hostID = Sys_GetHostId();
  445.         traceStartPtr->pageSize = vm_PageSize;
  446.         traceStartPtr->numPages = vmStat.numPhysPages;
  447.         traceStartPtr->codeStartAddr = mach_KernStart;
  448.         traceStartPtr->dataStartAddr = (Address)&etext;
  449.         traceStartPtr->stackStartAddr = vmStackBaseAddr;
  450.         traceStartPtr->mapStartAddr = vmMapBaseAddr;
  451.         traceStartPtr->cacheStartAddr = vmBlockCacheBaseAddr;
  452.         traceStartPtr->cacheEndAddr = vmBlockCacheEndAddr;
  453.         bcopy((Address)&vmStat, (Address)&traceStartPtr->startStats,
  454.             sizeof(Vm_Stat));
  455.         traceStartPtr->tracesPerSecond = vmTracesPerClock;
  456.         vmTraceFirstByte = 0;
  457.         vmTraceNextByte = sizeof(Vm_TraceStart);
  458.  
  459.         (void)strcpy(fileName, VM_TRACE_FILE_NAME);
  460.         (void)sprintf(hostNum, "%u", (unsigned) Sys_GetHostId());
  461.         (void)strcat(fileName, hostNum);
  462.  
  463.         status = Fs_Open(fileName, FS_WRITE | FS_CREATE,
  464.                  FS_FILE, 0660, &vmTraceFilePtr);
  465.         if (status != SUCCESS) {
  466.         printf("Warning: Vm_Cmd: Couldn't open trace file, reason %x\n",
  467.             status);
  468.         } else {
  469.         vmTraceNeedsInit = TRUE;
  470.         }
  471.         break;
  472.     }
  473.     case VM_END_TRACING: {
  474.         Vm_TraceEnd        traceEnd;
  475.  
  476.         bcopy((Address)&vmStat, (Address)&traceEnd.endStats,
  477.             sizeof(Vm_TraceEnd));
  478.         bcopy((Address)&vmTraceStats, (Address)&traceEnd.traceStats,
  479.             sizeof(Vm_TraceStats));
  480.         VmStoreTraceRec(VM_TRACE_END_REC, sizeof(Vm_TraceEnd),
  481.                 (Address)&traceEnd, FALSE);
  482.  
  483.         vm_Tracing = FALSE;
  484.         vmClockSleep = timer_IntOneSecond;
  485.         if (vmTraceFilePtr != (Fs_Stream *)NIL) {
  486.         VmTraceDump((ClientData)0, (Proc_CallInfo *)NIL);
  487.         (void)Fs_Close(vmTraceFilePtr);
  488.         vmTraceFilePtr = (Fs_Stream *)NIL;
  489.         }
  490.         printf("Vm_Cmd: Tracing ended: Traces=%d Drops=%d\n",
  491.             vmTraceTime, vmTraceStats.traceDrops);
  492.         printf("               Dumps=%d Bytes=%d.\n",
  493.             vmTraceStats.traceDumps, vmTraceNextByte);
  494.         break;
  495.     }
  496.     case VM_SET_WRITEABLE_PAGEOUT:
  497.         SETVAR(vmWriteablePageout, arg);
  498.         break;
  499.     case VM_SET_WRITEABLE_REF_PAGEOUT:
  500.         SETVAR(vmWriteableRefPageout, arg);
  501.         break;
  502.     case 1999:
  503.         SETVAR(vmShmDebug, arg);
  504.         break;
  505.     case 1234: /* Temporary unix compatibility hook. */
  506.         SETVAR(debugFsStubs, arg);
  507.         SETVAR(debugProcStubs, arg);
  508.         SETVAR(debugSigStubs, arg);
  509.         SETVAR(debugSysStubs, arg);
  510.         SETVAR(debugTimerStubs, arg);
  511.         SETVAR(debugVmStubs, arg);
  512.         default:
  513.         status = VmMach_Cmd(command, arg);
  514.             break;
  515.     }
  516.  
  517.     return(status);
  518. }
  519.  
  520.  
  521. /*
  522.  *----------------------------------------------------------------------
  523.  *
  524.  * SetVal --
  525.  *
  526.  *      Set a given VM variable.
  527.  *
  528.  * Results:
  529.  *      None.
  530.  *
  531.  * Side effects:
  532.  *      The given variable is set.
  533.  *
  534.  *----------------------------------------------------------------------
  535.  */
  536. void
  537. SetVal(descript, newVal, valPtr)
  538.     char    *descript;
  539.     int        newVal;
  540.     int        *valPtr;
  541. {
  542.     printf("%s val was %d, is %d\n", descript, *valPtr, newVal);
  543.     *valPtr = newVal;
  544. }
  545.  
  546. /*
  547.  *----------------------------------------------------------------------
  548.  *
  549.  * Vm_Mmap --
  550.  *
  551.  *    Map a page.
  552.  *
  553.  * Results:
  554.  *    Status from the map.
  555.  *
  556.  * Side effects:
  557.  *    Maps the page.
  558.  *
  559.  *----------------------------------------------------------------------
  560.  */
  561. /*ARGSUSED*/
  562. ENTRY ReturnStatus
  563. Vm_Mmap(startAddr, length, prot, share, streamID, fileAddr, mappedAddr)
  564.     Address    startAddr;    /* Requested starting virt-addr. */
  565.     int        length;        /* Length of mapped segment. */
  566.     int        prot;        /* Protection for mapped segment. */
  567.     int        share;        /* Private/shared flag. */
  568.     int        streamID;    /* Open file to be mapped. */
  569.     int        fileAddr;    /* Offset into mapped file. */
  570.     Address    *mappedAddr;    /* Mapped address (user space). */
  571. {
  572.     Address mappedAddrInt;
  573.     ReturnStatus status;
  574.  
  575.     status = Vm_MmapInt(startAddr, length, prot, share, streamID, fileAddr,
  576.         &mappedAddrInt);
  577.     if (status==SUCCESS) {
  578.     status = Vm_CopyOut(sizeof(int), (Address)&mappedAddrInt,
  579.         (Address)mappedAddr);
  580.     }
  581.     return status;
  582.     
  583. }
  584.  
  585. /*
  586.  *----------------------------------------------------------------------
  587.  *
  588.  * Vm_MmapInt --
  589.  *
  590.  *    Internal routine for Vm_Mmap.
  591.  *
  592.  * Results:
  593.  *    Status from the map.
  594.  *
  595.  * Side effects:
  596.  *    Maps the page.
  597.  *
  598.  *----------------------------------------------------------------------
  599.  */
  600. /*ARGSUSED*/
  601. ENTRY ReturnStatus
  602. Vm_MmapInt(startAddr, length, prot, share, streamID, fileAddr, mappedAddr)
  603.     Address    startAddr;    /* Requested starting virt-addr. */
  604.     int        length;        /* Length of mapped segment. */
  605.     int        prot;        /* Protection for mapped segment. */
  606.     int        share;        /* Private/shared flag. */
  607.     int        streamID;    /* Open file to be mapped. */
  608.     int        fileAddr;    /* Offset into mapped file. */
  609.     Address    *mappedAddr;    /* Mapped address. */
  610. {
  611.     Proc_ControlBlock    *procPtr;
  612.     Fs_Stream         *streamPtr;
  613.     int            pnum;
  614.     ReturnStatus    status = SUCCESS;
  615.     Fs_Attributes    attr;
  616.     Vm_SharedSegTable    *segTabPtr;
  617.     Vm_Segment        *segPtr;
  618.     Vm_SegProcList    *sharedSeg;
  619.     Fs_Stream         *filePtr;
  620.  
  621.     length = (length+vm_PageSize-1)&~(vm_PageSize-1);
  622.     dprintf("mmap( %x, %d, %d, %d, %d, %d)\n", startAddr, length,
  623.         prot, share, streamID, fileAddr);
  624.  
  625.     if ((share&MAP_TYPE)!=MAP_SHARED && (share&MAP_TYPE)!=MAP_PRIVATE) {
  626.     printf("Vm_Mmap: Invalid share flag %x\n", share);
  627.         return VM_WRONG_SEG_TYPE;
  628.     }
  629.  
  630.     procPtr = Proc_GetCurrentProc();
  631.     status = Fs_GetStreamPtr(procPtr,streamID,&streamPtr);
  632.     dprintf("Vm_Mmap: procPtr: %x  streamID: %d streamPtr: %x\n",
  633.         procPtr,streamID,(int)streamPtr);
  634.     if (status != SUCCESS) {
  635.     printf("Vm_Mmap: Fs_GetStreamPtr failure\n");
  636.     return status;
  637.     }
  638.     if (debugVmStubs) {
  639.     printf("mmap: refCount = %d  ",
  640.         ((Fs_HandleHeader *)streamPtr)->refCount);
  641.     }
  642.     Fsio_StreamCopy(streamPtr,&filePtr);
  643.     if (debugVmStubs) {
  644.     printf(", refCount = %d\n", ((Fs_HandleHeader *)streamPtr)->refCount);
  645.     }
  646.  
  647.     status = Fs_GetAttrStream(filePtr,&attr);
  648.     if (status != SUCCESS) {
  649.     printf("Vm_Mmap: Fs_GetAttrStream failure\n");
  650.     (void)Fs_Close(filePtr);
  651.     return status;
  652.     }
  653.     dprintf("file: fileNumber %d size %d\n",attr.fileNumber, attr.size);
  654.  
  655.     if (!(attr.type == FS_DEVICE) &&
  656.             (BADALIGN(startAddr) || BADALIGN(fileAddr))) {
  657.         printf("Vm_Mmap: Invalid start or offset\n");
  658.         return VM_WRONG_SEG_TYPE;
  659.     }
  660.     /*
  661.      * Do a device-specific mmap.
  662.      */
  663.     if (attr.type == FS_DEVICE) {
  664.         extern  ReturnStatus    Fsio_DeviceMmap();
  665.  
  666.         (void) Fs_Close(filePtr);               /* Don't need this filePtr. */
  667.         /*
  668.          * Should I really indirect through the file system here?  But that
  669.          * requires adding an mmap switch to all the file system crud.  I'll
  670.          * test it this way first by going straight to Fs_Device stuff.
  671.          */
  672.         status = Fsio_DeviceMmap(streamPtr, startAddr, length, fileAddr,
  673.                 &startAddr);
  674.         if (status == SUCCESS) {
  675.         *mappedAddr = startAddr;
  676.         }
  677.     return status;
  678.     }
  679.  
  680.  
  681.     /* 
  682.      * Check permissions.
  683.      * The rules:
  684.      * The file must have read permissions.
  685.      * We must request read and/or write permissions.
  686.      * If we take a private copy, we can do whatever we want.
  687.      * Otherwise we must have the requested permissions.
  688.      */
  689.     if (attr.type != FS_FILE) {
  690.     printf("Vm_Mmap: not a file\n");
  691.     (void)Fs_Close(filePtr);
  692.     return VM_WRONG_SEG_TYPE;
  693.     }
  694.     if (!(filePtr->flags & FS_READ) || !(prot & (PROT_READ | PROT_WRITE)) ||
  695.         ((share&MAP_TYPE)!=MAP_PRIVATE &&
  696.         (((prot & PROT_WRITE) && !(filePtr->flags & FS_WRITE)) ||
  697.         ((prot & PROT_EXEC) && !(filePtr->flags & FS_EXECUTE))))) {
  698.     printf("Vm_Mmap: protection failure\n");
  699.     printf("flags = %x, prot = %x\n", filePtr->flags, prot);
  700.     (void)Fs_Close(filePtr);
  701.     return VM_WRONG_SEG_TYPE;
  702.     }
  703.  
  704.     LOCK_SHM_MONITOR;
  705.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL) {
  706.     dprintf("Vm_Mmap: New proc list\n");
  707.     procPtr->vmPtr->sharedSegs = (List_Links *)
  708.         malloc(sizeof(Vm_SegProcList));
  709.     if (debugVmStubs) {
  710.         printf("Malloc'd segProcList: %x\n", procPtr->vmPtr->sharedSegs);
  711.     }
  712.     VmMach_SharedProcStart(procPtr);
  713.     dprintf("Vm_Mmap: sharedStart: %x\n",procPtr->vmPtr->sharedStart);
  714.     List_Init((List_Links *)procPtr->vmPtr->sharedSegs);
  715.     Proc_NeverMigrate(procPtr);
  716.     }
  717.     if (!(share&MAP_FIXED) || startAddr==0) {
  718.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 0);
  719.     } else {
  720.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 1);
  721.     }
  722.     if (status != SUCCESS) {
  723.     printf("Vm_Mmap: VmMach_SharedStart failure\n");
  724.     UNLOCK_SHM_MONITOR;
  725.     (void)Fs_Close(filePtr);
  726.     return status;
  727.     }
  728.  
  729.     /*
  730.      * See if a shared segment is already using the specified file.
  731.      * If we're making a private copy, we probably need a new segment.
  732.      * (We should probably do something more intelligent about mapping
  733.      * multiple copies of a file into memory.)
  734.      */
  735.     segPtr = (Vm_Segment *) NIL;
  736.     segTabPtr = (Vm_SharedSegTable *) NIL;
  737.     if ((share&MAP_TYPE)!=MAP_PRIVATE) {
  738.     LIST_FORALL((List_Links *)&sharedSegTable, (List_Links *)segTabPtr) {
  739.         if (segTabPtr->serverID == attr.serverID && segTabPtr->domain ==
  740.             attr.domain && segTabPtr->fileNumber == attr.fileNumber) {
  741.         segPtr = segTabPtr->segPtr;
  742.         break;
  743.         }
  744.     }
  745.     }
  746.  
  747. #if 0
  748.     pnum = 10288;    /* Random number, since shared memory shouldn't
  749.                 be using this value */
  750. #else
  751.     pnum = (int)startAddr>>vmPageShift;
  752. #endif
  753.  
  754.     if (segPtr == (Vm_Segment *)NIL) {
  755.     dprintf("Vm_Mmap: New segment\n");
  756.     /*
  757.      * Create a new segment and add to the shared segment list.
  758.      */
  759.     
  760.     segTabPtr = (Vm_SharedSegTable*) malloc(sizeof(Vm_SharedSegTable));
  761.     dprintf("Vm_Mmap: creating new segment\n");
  762.     segTabPtr->segPtr = Vm_SegmentNew(VM_SHARED,(Fs_Stream *)NIL,
  763.         0,length>>vmPageShift,pnum,procPtr);
  764.     if ((share&MAP_TYPE)==MAP_PRIVATE) {
  765.         segTabPtr->segPtr->filePtr = filePtr;
  766.     } else {
  767.         segTabPtr->segPtr->filePtr = (Fs_Stream *)NIL;
  768.         segTabPtr->segPtr->swapFilePtr = filePtr;
  769.         segTabPtr->segPtr->flags |= VM_SWAP_FILE_OPENED;
  770.     }
  771.     if (debugVmStubs) {
  772.         printf("Created new segment %x\n", segTabPtr->segPtr->segNum);
  773.     }
  774.     segTabPtr->serverID = attr.serverID;
  775.     segTabPtr->domain = attr.domain;
  776.     segTabPtr->fileNumber = attr.fileNumber;
  777.     segTabPtr->refCount = 0;
  778.     dprintf("Vm_Mmap: Validating pages %x to %x\n",
  779.         pnum,pnum+(length>>vmPageShift)-1);
  780.     Vm_ValidatePages(segTabPtr->segPtr,pnum,pnum+(length>>vmPageShift)-1,
  781.         FALSE,TRUE);
  782.     List_Insert((List_Links *)segTabPtr,
  783.         LIST_ATFRONT((List_Links *)&sharedSegTable));
  784.     dprintf("Calling Fs_FileBeingMapped(1)\n");
  785.     Fs_FileBeingMapped(filePtr,1);
  786.     dprintf("Done Fs_FileBeingMapped(1)\n");
  787.     } else {
  788.     int i;
  789.     /*
  790.     startAddr = (Address)(segPtr->offset<<vmPageShift);
  791.     */
  792.     if (length > (segPtr->numPages<<vmPageShift)) {
  793.         dprintf("Vm_Mmap: Enlarging segment: 0 to %d\n",
  794.             ((int)length-1)>>vmPageShift);
  795.         status = VmAddToSeg(segPtr,segPtr->offset,segPtr->offset+
  796.             (length>>vmPageShift)-1);
  797.         if (status != SUCCESS) {
  798.         printf("VmAddToSeg failure\n");
  799.         UNLOCK_SHM_MONITOR;
  800.         (void)Fs_Close(filePtr);
  801.         return status;
  802.         }
  803.     }
  804.     for (i=0;i<32;i++) {
  805.         if (segPtr->ptPtr[i] & VM_VIRT_RES_BIT) {
  806.         dprintf("1");
  807.         } else {
  808.         dprintf("0");
  809.         }
  810.     }
  811.     dprintf("\n");
  812.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL ||
  813.         !VmCheckSharedSegment(procPtr,segPtr)) {
  814.         /*
  815.          * Process is not using segment.
  816.          */
  817.         dprintf("Vm_Mmap: Adding reference to proc to segment\n");
  818.         Vm_SegmentIncRef(segPtr,procPtr);
  819.     } else {
  820.         /*
  821.          * Process is already using segment.
  822.          */
  823.         dprintf("Vm_Mmap: Process is using segment.\n");
  824.     }
  825.     }
  826.  
  827.     /*
  828.      * Unmap any current mapping at the address range.
  829.      */
  830.     status=VmMunmapInt(startAddr,length,1);
  831.     if (status == SUCCESS) {
  832.     /*
  833.      * Force the mach module to allocate the segment again.
  834.      * (The allocation of shared segments in memory needs to be fixed up.
  835.      * The problem is that we may have multiple segments mapped into
  836.      * the same memory, and thus it is hard to keep track of what's
  837.      * in use).  This should force the segment to be marked as in use.
  838.      * There still may be a problem if part of a segment is unmapped.
  839.      */
  840.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 1);
  841.     }
  842.     if (status != SUCCESS) {
  843.     printf("Vm_Mmap: Vm_Munmap failure\n");
  844.     UNLOCK_SHM_MONITOR;
  845.     (void)Fs_Close(filePtr);
  846.     return status;
  847.     }
  848.  
  849.     /*
  850.      * Add the segment to the process's list of shared segments.
  851.      */
  852.     dprintf("Vm_Mmap: Adding segment to list\n");
  853.     sharedSeg = (Vm_SegProcList *)malloc(sizeof(Vm_SegProcList));
  854.     if (debugVmStubs) {
  855.     printf("Malloc'd segProcList: %x\n", sharedSeg);
  856.     }
  857.     sharedSeg->fd = streamID;
  858.     sharedSeg->stream = filePtr;
  859.     sharedSeg->segTabPtr = segTabPtr;
  860.     segTabPtr->refCount++;
  861.     sharedSeg->addr = startAddr;
  862.     sharedSeg->mappedStart = startAddr;
  863.     dprintf("fileAddr: %x\n",fileAddr);
  864.     sharedSeg->fileAddr = fileAddr;
  865.     sharedSeg->offset = (int)startAddr>>vmPageShift;
  866.     sharedSeg->mappedEnd = startAddr+length-1;
  867.     sharedSeg->prot = (prot&PROT_WRITE) ? 0 : VM_READONLY_SEG;
  868.     dprintf("Set prot to %d\n",sharedSeg->prot);
  869.     if ((int)sharedSeg->segTabPtr == -1) {
  870.     dprintf("Vm_Mmap: Danger: sharedSeg->segTabPtr is -1!\n");
  871.     }
  872.     List_Insert((List_Links *)sharedSeg,
  873.         LIST_ATFRONT((List_Links *)procPtr->vmPtr->sharedSegs));
  874.     
  875.  
  876.     VmPrintSharedSegs(procPtr);
  877.     UNLOCK_SHM_MONITOR;
  878.     dprintf("Vm_Mmap: Completed page mapping\n");
  879.     *mappedAddr = startAddr;
  880.     return SUCCESS;
  881. }
  882.  
  883. /*
  884.  *----------------------------------------------------------------------
  885.  *
  886.  * Vm_Munmap --
  887.  *
  888.  *    Unmaps the process's pages in a specified address range.
  889.  *    Gets the lock and then calls VmMunmapInt.
  890.  *
  891.  * Results:
  892.  *    Status from the unmap operation.
  893.  *
  894.  * Side effects:
  895.  *    Unmaps the pages.
  896.  *
  897.  *----------------------------------------------------------------------
  898.  */
  899. ReturnStatus
  900. Vm_Munmap(startAddr, length, noError)
  901.     Address    startAddr;    /* Starting virt-addr. */
  902.     int        length;        /* Length of mapped segment. */
  903.     int        noError;    /* Ignore errors. */
  904. {
  905.     ReturnStatus status;
  906.  
  907.     dprintf("munmap(%x, %d, %d)\n", startAddr, length, noError);
  908.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  909.     printf("Vm_Munmap: Invalid start or offset\n");
  910.     return VM_WRONG_SEG_TYPE;
  911.     }
  912.     LOCK_SHM_MONITOR;
  913.     status = VmMunmapInt(startAddr,length, noError);
  914.     UNLOCK_SHM_MONITOR;
  915.     return status;
  916. }
  917.  
  918. /*
  919.  *----------------------------------------------------------------------
  920.  *
  921.  * VmMunmapInt --
  922.  *
  923.  *    Unmaps the process's pages in a specified address range.
  924.  *
  925.  * Results:
  926.  *    Status from the unmap operation.
  927.  *
  928.  * Side effects:
  929.  *    Unmaps the pages.
  930.  *
  931.  *----------------------------------------------------------------------
  932.  */
  933. static ReturnStatus
  934. VmMunmapInt(startAddr, length, noError)
  935.     Address    startAddr;    /* Starting virt-addr. */
  936.     int        length;        /* Length of mapped segment. */
  937.     int        noError;    /* 1 if don't care about errors
  938.                    from absent segments. */
  939. {
  940.  
  941.     ReturnStatus    status = SUCCESS;
  942.     Proc_ControlBlock    *procPtr;
  943.     Vm_SegProcList        *segProcPtr;
  944.     Vm_SegProcList        *newSegProcPtr;
  945.     Address        addr;
  946.     Address        addr1;
  947.     Address        endAddr;
  948.     Vm_VirtAddr        virtAddr;
  949.  
  950.     virtAddr.flags = 0;
  951.     virtAddr.offset = 0;
  952.  
  953.     dprintf("Vm_Munmap: Unmapping shared pages\n");
  954.  
  955.     procPtr = Proc_GetCurrentProc();
  956.     endAddr = startAddr+length;
  957.     for (addr=startAddr; addr<endAddr; ) {
  958.  
  959.     dprintf("Vm_Munmap: trying to eliminate %x to %x\n",
  960.         (int)addr,(int)endAddr-1);
  961.     /* Find the segment corresponding to this address. */
  962.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  963.         segProcPtr = VmFindSharedSegment(procPtr->vmPtr->sharedSegs,addr);
  964.     } else if (noError) {
  965.         return SUCCESS;
  966.     } else {
  967.         dprintf("Vm_Munmap: Process has no shared segments\n");
  968.         return VM_WRONG_SEG_TYPE;
  969.     }
  970.  
  971.     /* There are three possibilities:
  972.        1. The unmap can remove a mapping.
  973.        2. The unmap can shrink a mapping.
  974.        3. The unmap can split a mapping.
  975.     */
  976.  
  977.     if (segProcPtr == (Vm_SegProcList *)NIL) {
  978.         if (!noError) {
  979.         dprintf("Vm_Munmap: Page to unmap not in valid range\n");
  980.         status = VM_WRONG_SEG_TYPE;
  981.         }
  982.         /*
  983.          * Move to next mapped segment, so we can keep unmapping.
  984.          */
  985.         addr1 = endAddr;
  986.         LIST_FORALL(procPtr->vmPtr->sharedSegs,
  987.             (List_Links *)segProcPtr) {
  988.         if (segProcPtr->mappedStart > addr && 
  989.             segProcPtr->mappedStart < addr1) {
  990.             addr1 = segProcPtr->mappedStart;
  991.         }
  992.         }
  993.     } else {
  994.         addr1 = segProcPtr->mappedEnd+1;
  995.  
  996.         /*
  997.          * Invalidate the pages to be mapped out.
  998.          */
  999.         virtAddr.page = max((int)segProcPtr->mappedStart,(int)addr)
  1000.             >> vmPageShift;
  1001.         virtAddr.segPtr = segProcPtr->segTabPtr->segPtr;
  1002.         virtAddr.sharedPtr = segProcPtr;
  1003.         dprintf("Vm_Munmap: invalidating: %x to %x\n",
  1004.             (int)virtAddr.page<<vmPageShift,
  1005.             min((int)segProcPtr->mappedEnd+1, (int)endAddr));
  1006.         VmFlushSegment(&virtAddr,min((int)segProcPtr->mappedEnd+1,
  1007.             (int)endAddr)>>vmPageShift);
  1008.  
  1009.         if (segProcPtr->mappedStart < addr) {
  1010.         dprintf("Vm_Munmap: Shortening mapped region (1)\n");
  1011.         if (segProcPtr->mappedEnd >= endAddr) {
  1012.             dprintf("Vm_Munmap: Splitting mapped region\n");
  1013.             /*
  1014.              * Split the mapped region.
  1015.              */
  1016.             newSegProcPtr = (Vm_SegProcList *)
  1017.                 malloc(sizeof(Vm_SegProcList));
  1018.             if (debugVmStubs) {
  1019.             printf("Malloc'd %x\n", newSegProcPtr);
  1020.             }
  1021.             *newSegProcPtr = *segProcPtr;
  1022.             newSegProcPtr->mappedStart = endAddr;
  1023.             newSegProcPtr->mappedEnd = segProcPtr->mappedEnd;
  1024.             segProcPtr->segTabPtr->refCount++;
  1025.             List_Insert((List_Links *)newSegProcPtr, LIST_AFTER(
  1026.                 (List_Links *)segProcPtr));
  1027.         }
  1028.         /*
  1029.          * Shrink the first mapping.
  1030.          */
  1031.         segProcPtr->mappedEnd = addr-1;
  1032.         } else if (segProcPtr->mappedEnd >= endAddr) {
  1033.         /*
  1034.          * Shrink the mapped region.
  1035.          */
  1036.         dprintf("Vm_Munmap: Shortening mapped region (2)\n");
  1037.         segProcPtr->mappedStart = endAddr;
  1038.         } else {
  1039.         dprintf("Vm_Munmap: Removing mapped region\n");
  1040.         /*
  1041.          * Remove the entire mapped region.
  1042.          */
  1043.         Vm_DeleteSharedSegment(procPtr,segProcPtr);
  1044.         }
  1045.     }
  1046.     if (addr == addr1) {
  1047.         panic("Vm_Munmap loop\n");
  1048.     }
  1049.     addr = addr1;
  1050.     }
  1051.  
  1052.     VmPrintSharedSegs(procPtr);
  1053.     dprintf("Vm_Munmap: done\n");
  1054.     return status ;
  1055. }
  1056.  
  1057. /* 
  1058.  * Check if an address range is valid for the segment.
  1059.  */
  1060. #define CheckBounds(virtAddrPtr,startAddr,length) \
  1061.     ((unsigned)(((int)(startAddr)>>vmPageShift) - segOffset(virtAddrPtr)) \
  1062.     < (virtAddrPtr)->segPtr->ptSize && \
  1063.     ((unsigned)((((int)(startAddr)+(length)-1)>>vmPageShift) - \
  1064.     segOffset(virtAddrPtr)) < (virtAddrPtr)->segPtr->ptSize))
  1065. /*
  1066.  *----------------------------------------------------------------------
  1067.  *
  1068.  * Vm_Msync --
  1069.  *
  1070.  *    Sync pages to disk.
  1071.  *    startAddr and length must be divisible by the page size.
  1072.  *
  1073.  * Results:
  1074.  *    Status from the sync.
  1075.  *
  1076.  * Side effects:
  1077.  *    Page goes to disk.
  1078.  *
  1079.  *----------------------------------------------------------------------
  1080.  */
  1081. ENTRY ReturnStatus
  1082. Vm_Msync(startAddr, length)
  1083.     Address    startAddr;    /* Requested starting virt-addr. */
  1084.     int        length;        /* Length of region to page out. */
  1085. {
  1086.     Vm_VirtAddr        virtAddr;
  1087.     ReturnStatus    status;
  1088.     Proc_ControlBlock    *procPtr;
  1089.  
  1090.     dprintf("msync( %x, %d)\n", startAddr, length);
  1091.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1092.     printf("Vm_Msync: Invalid start or offset\n");
  1093.     return VM_WRONG_SEG_TYPE;
  1094.     }
  1095.     LOCK_SHM_MONITOR;
  1096.     procPtr = Proc_GetCurrentProc();
  1097.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1098.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1099.         startAddr, length)) {
  1100.     UNLOCK_SHM_MONITOR;
  1101.     return SYS_INVALID_ARG;
  1102.     }
  1103.     status = VmPageFlush(&virtAddr, length, TRUE, TRUE);
  1104.     UNLOCK_SHM_MONITOR;
  1105.     return status;
  1106. }
  1107.  
  1108. /*
  1109.  *----------------------------------------------------------------------
  1110.  *
  1111.  * Vm_Mlock --
  1112.  *
  1113.  *    Locks a page into memory.  Page is paged in if necessary.
  1114.  *
  1115.  * Results:
  1116.  *    Fails if unable to lock page.
  1117.  *
  1118.  * Side effects:
  1119.  *    Locks the page.
  1120.  *
  1121.  *----------------------------------------------------------------------
  1122.  */
  1123. /*ARGSUSED*/
  1124. ENTRY ReturnStatus
  1125. Vm_Mlock(startAddr, length)
  1126.     Address    startAddr;    /* Requested starting virt-addr. */
  1127.     int        length;        /* Length of region to lock. */
  1128. {
  1129.     Vm_VirtAddr        virtAddr;
  1130.     Proc_ControlBlock    *procPtr;
  1131.     int            maptype = VM_READWRITE_ACCESS;
  1132.  
  1133.     dprintf("mlock( %x, %d)\n", startAddr, length);
  1134.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1135.     printf("Vm_Mlock: Invalid start or offset\n");
  1136.     return VM_WRONG_SEG_TYPE;
  1137.     }
  1138.     procPtr = Proc_GetCurrentProc();
  1139.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1140.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1141.         startAddr, length)) {
  1142.     return SYS_INVALID_ARG;
  1143.     } else if (virtAddr.sharedPtr != (Vm_SegProcList *)NIL) {
  1144.     maptype = virtAddr.sharedPtr->prot == VM_READONLY_SEG ?
  1145.         VM_READONLY_ACCESS : VM_READWRITE_ACCESS;
  1146.     } else {
  1147.     maptype = virtAddr.segPtr->type == VM_CODE ? VM_READONLY_ACCESS :
  1148.         VM_READWRITE_ACCESS;
  1149.     }
  1150.     return Vm_PinUserMem(maptype,length,startAddr);
  1151. }
  1152.  
  1153. /*
  1154.  *----------------------------------------------------------------------
  1155.  *
  1156.  * Vm_Munlock --
  1157.  *
  1158.  *    Unlocks a page.
  1159.  *
  1160.  * Results:
  1161.  *    Status from the unlock.
  1162.  *
  1163.  * Side effects:
  1164.  *    Unlocks the page.
  1165.  *
  1166.  *----------------------------------------------------------------------
  1167.  */
  1168. /*ARGSUSED*/
  1169. ENTRY ReturnStatus
  1170. Vm_Munlock(startAddr, length)
  1171.     Address    startAddr;    /* Requested starting virt-addr. */
  1172.     int        length;        /* Length of region to unlock. */
  1173. {
  1174.     Vm_VirtAddr    virtAddr;
  1175.     Proc_ControlBlock    *procPtr;
  1176.  
  1177.     dprintf("munlock( %x, %d)\n", startAddr, length);
  1178.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1179.     printf("Vm_Munlock: Invalid start or offset\n");
  1180.     return VM_WRONG_SEG_TYPE;
  1181.     }
  1182.     procPtr = Proc_GetCurrentProc();
  1183.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1184.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1185.         startAddr, length)) {
  1186.     return SYS_INVALID_ARG;
  1187.     }
  1188.     Vm_UnpinUserMem(length,startAddr);
  1189.     return SUCCESS;
  1190. }
  1191.  
  1192. /*
  1193.  *----------------------------------------------------------------------
  1194.  *
  1195.  * Vm_Mincore --
  1196.  *
  1197.  *    Returns residency vector.
  1198.  *
  1199.  * Results:
  1200.  *    The values of vec are 0 if the page is not virtually resident,
  1201.  *    1 if the page is paged out, 2 if the page is clean and
  1202.  *    untouched, 3 if the page is referenced, and 4 if the page is dirty.
  1203.  *
  1204.  * Side effects:
  1205.  *    None.
  1206.  *
  1207.  *----------------------------------------------------------------------
  1208.  */
  1209. /*ARGSUSED*/
  1210.  
  1211. ENTRY ReturnStatus
  1212. Vm_Mincore(startAddr, length, retVec)
  1213.     Address    startAddr;    /* Requested starting virt-addr. */
  1214.     int        length;        /* Length of region. */
  1215.     char *    retVec;        /* Return vector. */
  1216. {
  1217.     char        *vec;
  1218.     Address        checkAddr;
  1219.     Vm_VirtAddr        virtAddr;
  1220.     Proc_ControlBlock    *procPtr;
  1221.     ReturnStatus    status;
  1222.     int            len;
  1223.     int            i;
  1224.     Vm_PTE        *ptePtr;
  1225.     Boolean        referenced;
  1226.     Boolean        modified;
  1227.  
  1228.     dprintf("mincore( %x, %d, %x)\n", startAddr, length, retVec);
  1229.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1230.     printf("Vm_Mincore: Invalid start or offset\n");
  1231.     return VM_WRONG_SEG_TYPE;
  1232.     }
  1233.     procPtr = Proc_GetCurrentProc();
  1234.     len = length>>vmPageShift;
  1235.     vec = (char *)malloc(len);
  1236.     checkAddr = startAddr;
  1237.     for (i=0;i<len;i++) {
  1238.     VmVirtAddrParseUnlock(procPtr, checkAddr, &virtAddr);
  1239.     if (virtAddr.segPtr == (Vm_Segment *)NIL) {
  1240.         vec[i] = 0;
  1241.         dprintf("Vm_Mincore: no segment at address %x\n", checkAddr);
  1242.     } else {
  1243.         ptePtr = VmGetAddrPTEPtr(&virtAddr, virtAddr.page);
  1244.         if (*ptePtr & VM_VIRT_RES_BIT) {
  1245.         if (*ptePtr & VM_PHYS_RES_BIT) {
  1246.             VmMach_GetRefModBits(&virtAddr, Vm_GetPageFrame(*ptePtr),
  1247.                 &referenced, &modified);
  1248.             if (modified || (*ptePtr & VM_MODIFIED_BIT)) {
  1249.             vec[i] = 4;
  1250.             dprintf("Vm_Mincore: modified at %x\n", checkAddr);
  1251.             } else if (referenced || (*ptePtr & VM_REFERENCED_BIT)) {
  1252.             vec[i] = 3;
  1253.             dprintf("Vm_Mincore: referenced at %x\n", checkAddr);
  1254.             } else {
  1255.             vec[i] = 2;
  1256.             dprintf("Vm_Mincore: present at %x\n", checkAddr);
  1257.             }
  1258.         } else {
  1259.             vec[i] = 1;
  1260.             dprintf("Vm_Mincore: absent at %x\n", checkAddr);
  1261.         }
  1262.         } else {
  1263.         vec[i] = 0;
  1264.         dprintf("Vm_Mincore: gone at %x\n", checkAddr);
  1265.         }
  1266.     }
  1267.     checkAddr += vm_PageSize;
  1268.     dprintf("Vm_Mincore: i=%d v[i]=%d\n",i,vec[i]);
  1269.     }
  1270.     status = Vm_CopyOut( len, (Address) vec, (Address) retVec);
  1271.     free((char *)vec);
  1272.     return status;
  1273. }
  1274.  
  1275. /*
  1276.  *----------------------------------------------------------------------
  1277.  *
  1278.  * Vm_Mprotect --
  1279.  *
  1280.  *    Change protection of pages.
  1281.  *
  1282.  * Results:
  1283.  *    SUCCESS or error condition.
  1284.  *
  1285.  * Side effects:
  1286.  *    Changes protection.
  1287.  *
  1288.  *----------------------------------------------------------------------
  1289.  */
  1290.  
  1291. ENTRY ReturnStatus
  1292. Vm_Mprotect(startAddr, length, prot)
  1293.     Address    startAddr;    /* Requested starting virt-addr. */
  1294.     int        length;        /* Length of region. */
  1295.     int        prot;        /* Protection for region. */
  1296. {
  1297.     Vm_VirtAddr virtAddr;
  1298.     Vm_PTE          *ptePtr;
  1299.     Proc_ControlBlock       *procPtr;
  1300.     int i;
  1301.     int firstPage, lastPage;
  1302.  
  1303.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1304.     printf("Vm_Mprotect: Invalid start or offset\n");
  1305.     return VM_WRONG_SEG_TYPE;
  1306.     }
  1307. #if 0
  1308.     if (prot & ~(PROT_READ|PROT_WRITE)) {
  1309.     printf("Vm_Mprotect: Only read/write permissions allowed\n");
  1310.     return SYS_INVALID_ARG;
  1311.     }
  1312. #endif
  1313.     if (!(prot & PROT_READ)) {
  1314.     printf("Vm_Mprotect: can't remove read perms in this implementation\n");
  1315.     return SYS_INVALID_ARG;
  1316.     }
  1317.     procPtr = Proc_GetCurrentProc();
  1318.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1319.     firstPage = (unsigned int) startAddr >> vmPageShift;
  1320.     lastPage = ((unsigned int)(startAddr+length-1)) >> vmPageShift;
  1321.     if (firstPage < segOffset(&virtAddr)) {
  1322.     printf("First page is out of range\n");
  1323.     return SYS_INVALID_ARG; /* ENOMEM */
  1324.     }
  1325.     for (i=lastPage-firstPage, ptePtr =
  1326.         VmGetAddrPTEPtr(&virtAddr, virtAddr.page);i>=0;
  1327.         i--, VmIncPTEPtr(ptePtr,1), virtAddr.page++) {
  1328.     if (lastPage >= segOffset(&virtAddr) + virtAddr.segPtr->ptSize) {
  1329.         printf("Page out of range\n");
  1330.         return SYS_INVALID_ARG; /* ENOMEM */
  1331.     }
  1332.     if (prot & PROT_WRITE) {
  1333.         *ptePtr &= ~VM_READ_ONLY_PROT;
  1334.     } else {
  1335.         *ptePtr |= VM_READ_ONLY_PROT;
  1336.     }
  1337.     VmMach_SetPageProt(&virtAddr, *ptePtr);
  1338.     }
  1339.     return SUCCESS;
  1340. }
  1341.